﻿using System.Data.Common;
using System.Drawing;

namespace TextureGenerator.Mechanics
{
    public class GaussianBlur
    {
        GaussianKernel gk;
        int r;
        int length;
        float sigma;
        public GaussianBlur(int r,float sigma)
        {
            gk = new(r, sigma);
            length = 2 * r + 1;
            this.r = r;
            this.sigma = sigma;
        }
        public void Run(string filename)
        {
            Bitmap input = (Bitmap)Image.FromFile($"img/{filename}");
            Bitmap output = new Bitmap(input.Width, input.Height);
            Color[,] temp = new Color[length,length];
            for(int x = 0; x < input.Width; x++)
            {
                for(int y = 0; y < input.Height; y++)
                {
                    CounterMap(x, y, temp, input);
                    output.SetPixel(x,y,gk.MutAndSum(temp));
                }
            }
            input.Dispose();
            output.Save("img/output.png", System.Drawing.Imaging.ImageFormat.Png);
            output.Dispose();
        }
        public void CounterMap(int x,int y, Color[,] temp,Bitmap input)
        {
            int width = input.Width;
            int height = input.Height;
            Func<int, int, bool> isIn = (x, y) => x >= 0 && x < width && y >= 0 && y < height;
            for(int i=0;i<length;i++)
            {
                int u = i - r;
                for(int j=0;j<length;j++)
                {
                    int v = j - r;
                    int tarX = u + x;
                    int tarY = v + y;
                    if (isIn(tarX, tarY))
                    {
                        temp[i, j] = input.GetPixel(tarX, tarY);
                    }
                    else
                    {
                        temp[i, j] = Color.White;
                    }
                }
            }
        }
    }
    public class GaussianKernel
    {
        float[,] G;
        int r;
        int length;
        public GaussianKernel(int r,float sigma)
        {
            this.r = r;
            length = 2 * r + 1;
            G = new float[length,length];

            float k1 = 1 / (2*MathF.PI*sigma*sigma);
            float k2 = 2 * sigma * sigma;
            for(int i = 0; i < length; i++)
            {
                int u = -r + i;
                for(int j = 0; j < length; j++)
                {
                    int v = -r + j;
                    G[i, j] = k1 * MathF.Exp(-(u * u + v * v) / k2);
                }
            }
        }
        public float Get(int u,int v)
        {
            int i = u + r;
            int j = v + r;
            return G[i, j];
        }
        public Color MutAndSum(Color[,] input)
        {
            float r = 0, g = 0, b = 0;
            for(int i = 0; i < length; i++)
            {
                for(int j = 0; j < length; j++)
                {
                    for(int k = 0; k < length; k++)
                    {
                        Color c1 = input[i, k];
                        Color c2 = input[k, j];
                        float f1 = G[k, j];
                        float f2 = G[i, k];
                        r += c1.R * f1 + c2.R * f2;
                        g += c1.G * f1 + c2.G * f2;
                        b += c1.B * f1 + c2.B * f2;
                    }
                }
            }
            int num = length*2;
            int resR = (int)(r / num);
            int resG = (int)(g / num);
            int resB = (int)(b / num);
            return Color.FromArgb(resR, resG, resB);
        }
    }
}
